package xiaohong.jvm;

import java.util.LinkedList;
import java.util.List;

/**
 * StopWorld测试
 */

//一个线程定时打印时间用作模拟用户线程
//一个线程用来不停填充数据用作模拟产生Full GC
//观察对比打印的时间间隔是不是一直处于100ms, 尤其是发生GC的前后两次打印
//运行前配置VM Options:
//-Xms300M -Xms300M -XX:+UseSerialGC -XX:+PrintGCDetails
public class StopWorldTest {

    //不停往list中填充数据
    public static class FillListThread extends Thread {
        List<byte[]> list = new LinkedList<>();
        @Override
        public void run() {
            try {
                while(true) {
                    //当list到达990M时清空list
                    if (list.size() * 512 / 1024 / 1024 >= 990) {
                        list.clear();
                        System.out.println("list is clear");
                    }
                    byte[] bl;
                    for (int i=0;i<100;i++) {
                        bl = new byte[2 * 1024 * 1024];
                        list.add(bl);
                    }
                    Thread.sleep(1);
                }
            } catch (Exception e) {
//                e.printStackTrace();
            }
        }
    }

    //每100ms定时打印
    public static class TimerThread extends Thread {
        public final static long startTime = System.currentTimeMillis();
        @Override
        public void run() {
            try {
                while(true) {
                    long t =  System.currentTimeMillis() - startTime;
                    System.out.println(t / 1000 + "." + t % 1000);
                    Thread.sleep(100);
                }
            } catch (Exception e) {
//                e.printStackTrace();
            }
        }
    }

    //从输出结果中可见, 在发生GC的前后两次时间打印是大于100ms的,
    //而其他时候的两次打印之间相差基本是100ms, 从而验证了GC会StopTheWorld
    //部分输出结果如下:
    //...
    //2.264
    //2.367
    //2.467
    //2.571
    //[GC (Allocation Failure) [...] [Times: user=0.24 sys=0.19, real=0.79 secs] (这次gc用了790ms)
    //3.410
    //...
    public static void main(String[] args) {
        FillListThread myThread = new FillListThread();
        TimerThread timerThread = new TimerThread();
        myThread.start();
        timerThread.start();
    }

}
